﻿using System;
using System.Collections.Generic;

using System.Text;
using GGSharp.Packets;
using GGSharp.Structures;

namespace GGSharp
{
    public class GGUserList : List<GGContact>
    {
        protected const int MAX_REQUEST_SIZE = 2040;

        public event EventHandler UserListImported;
        public event EventHandler UserListExported;

        GGSender _sender;
        GGReceiver _receiver;

        protected string _importedListText = "";
        private bool _autoNotifyServer = true;

        private bool _notifySent = false;

        public GGUserList(GGSender sender, GGReceiver receiver)
        {
            _sender = sender;
            _receiver = receiver;
            _receiver.PacketReceived += _receiver_PacketReceived;
        }

        /// <summary>
        /// Gets or sets a value indicating whether user list is automatically send to server after login.
        /// </summary>
        /// <value><c>true</c> if list is automatically sent; otherwise, <c>false</c>.</value>
        public bool AutoNotifyServer
        {
            get { return _autoNotifyServer; }
            set { _autoNotifyServer = value; }
        }

        void _receiver_PacketReceived(object sender, GGSharp.Packets.HeaderPacket packet)
        {
            switch (packet.Type)
            {
                case PacketType.GG_LOGIN_OK:
                    if (AutoNotifyServer)
                        NotifyServer();
                    break;

                case PacketType.GG_USERLIST_REPLY:
                    UserListReplyPacket userListReply = (UserListReplyPacket)packet;
                    if (userListReply.ReplyType == UserListReplyType.GetMoreReply || userListReply.ReplyType == UserListReplyType.GetReply)
                    {
                        _importedListText += userListReply.Reply;
                        if (userListReply.ReplyType == UserListReplyType.GetReply)
                        {
                            ImportFromFile(_importedListText);
                            _importedListText = "";
                        }
                    }
                    break;
            }
        }

        /// <summary>
        /// Exports user list to the server.
        /// </summary>
        public void ExportToServer()
        {
            StringBuilder serverOutput = new StringBuilder();

            for (int i = 0; i < this.Count; i++)
                serverOutput.Append(GetContactText(this[i]) + "\n");

            string userListExport = serverOutput.ToString();
            int totalBytesSend = 0;
            int charsToSend = userListExport.Length - MAX_REQUEST_SIZE > 0 ? MAX_REQUEST_SIZE : userListExport.Length;

            //wyslij pierwszy pakiet o maksymalnej dlugosci MAX_REQUEST_SIZE
            UserListRequestPacket requestPacket = new UserListRequestPacket();
            requestPacket.RequestType = UserListRequestType.Put;
            requestPacket.Request = userListExport.Substring(0, charsToSend);
            totalBytesSend += requestPacket.Request.Length;
            _sender.Send(requestPacket);

            //wyslij kolejne pakiety o maksymalnej dlugosci MAX_REQUEST_SIZE
            while (totalBytesSend < userListExport.Length)
            {
                charsToSend = userListExport.Length - totalBytesSend - MAX_REQUEST_SIZE > 0 ? MAX_REQUEST_SIZE : userListExport.Length - totalBytesSend;

                requestPacket = new UserListRequestPacket();
                requestPacket.RequestType = UserListRequestType.PutMore;
                requestPacket.Request = userListExport.Substring(totalBytesSend, charsToSend);
                totalBytesSend += requestPacket.Request.Length;
                _sender.Send(requestPacket);
            }

            OnUserListExported();
        }

        protected GGContact GetContact(string contactText)
        {
            string[] fields = contactText.Split(';');
            if (fields.Length == 14)
            {
                GGContact contact = new GGContact();
                contact.Name = fields[0];
                contact.Surname = fields[1];
                contact.Nick = fields[2];
                contact.Title = fields[3];
                contact.CellNumber = fields[4];
                contact.Group = fields[5];
                contact.Number = Int32.Parse("0" + fields[6]);
                contact.Email = fields[7];
                contact.AvailableSound = Int32.Parse("0" + fields[8]);
                contact.AvailableSoundPath = fields[9];
                contact.MessageSound = Int32.Parse("0" + fields[10]);
                contact.MessageSoundPath = fields[11];
                contact.Hiding = Int32.Parse("0" + fields[12]);
                contact.HomeNumber = fields[13];

                return contact;
            }
            else
                return null;
        }

        protected string GetContactText(GGContact contact)
        {
            StringBuilder contactText = new StringBuilder();
            contactText.Append(contact.Name + ";");
            contactText.Append(contact.Surname + ";");
            contactText.Append(contact.Nick + ";");
            contactText.Append(contact.Title + ";");
            contactText.Append(contact.CellNumber + ";");
            contactText.Append(contact.Group + ";");
            contactText.Append(contact.Number + ";");
            contactText.Append(contact.Email + ";");
            contactText.Append(contact.AvailableSound + ";");
            contactText.Append(contact.AvailableSoundPath + ";");
            contactText.Append(contact.MessageSound + ";");
            contactText.Append(contact.MessageSoundPath + ";");
            contactText.Append(contact.Hiding + ";");
            contactText.Append(contact.HomeNumber);

            return contactText.ToString();
        }

        /// <summary>
        /// Imports user list from server.
        /// </summary>
        public void ImportFromServer()
        {
            UserListRequestPacket requestPacket = new UserListRequestPacket();
            requestPacket.RequestType = UserListRequestType.Get;
            _sender.Send(requestPacket);
        }

        /// <summary>
        /// Imports user list from file.
        /// </summary>
        /// <param name="fileContents">The file contents.</param>
        public void ImportFromFile(string fileContents)
        {
            string[] contacts = fileContents.Split('\n');

            for (int i = 0; i < contacts.Length; i++)
            {
                GGContact contact = GetContact(contacts[i]);
                if (contact != null)
                    this.Add(contact);
            }

            OnUserListImported();
        }

        /// <summary>
        /// Notifies server that we removed contact from our list (or unsets flags).
        /// </summary>
        /// <param name="notify">The notify.</param>
        public void RemoveServerNotify(NotifyStruct notify)
        {
            RemoveNotifyPacket removeNotify = new RemoveNotifyPacket(notify);
            _sender.Send(removeNotify);
        }

        /// <summary>
        /// Notifies server about our new contact on user list (or sets new flags).
        /// </summary>
        /// <param name="notify">The notify.</param>
        public void AddServerNotify(NotifyStruct notify)
        {
            AddNotifyPacket addNotify = new AddNotifyPacket(notify);
            _sender.Send(addNotify);
        }

        /// <summary>
        /// Notifies the server about our current user list.
        /// </summary>
        public void NotifyServer()
        {
            //jesli nie ma kontaktow to wiele do roboty nie ma
            if (this.Count == 0)
            {
                _sender.Send(new EmptyListPacket());
                _notifySent = true;
                return;
            }

            int sent = 0;

            //pack contacts in packets. Each containing 400 contacts
            while (this.Count - sent > 400)
            {
                NotifyFirstPacket notifyFirst = new NotifyFirstPacket();
                for (int i = 0; i < 400; i++)
                    notifyFirst.Contacts.Add(new NotifyStruct(this[sent++].Number));

                _sender.Send(notifyFirst);
            }

            //Send rest contacts in this packet
            int leftTosent = this.Count - sent;
            NotifyLastPacket notifyLast = new NotifyLastPacket();
            for (int i = 0; i < leftTosent; i++)
                notifyLast.Contacts.Add(new NotifyStruct(this[sent++].Number));

            _sender.Send(notifyLast);
            _notifySent = true;
        }

        protected void OnUserListExported()
        {
            if (UserListExported != null)
                UserListExported(this, EventArgs.Empty);
        }

        protected void OnUserListImported()
        {
            if (UserListImported != null)
                UserListImported(this, EventArgs.Empty);
        }
    }
}
